home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WINGs / wevent.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-28  |  24.8 KB  |  1,045 lines

  1.  
  2.  
  3. /*
  4.  * This event handling stuff was based on Tk.
  5.  */
  6.  
  7. #include "WINGsP.h"
  8.  
  9. #include "../src/config.h"
  10.  
  11. #include <sys/types.h>
  12. #include <unistd.h>
  13.  
  14. #ifdef HAVE_POLL_H
  15. #include <poll.h>
  16. #endif
  17.  
  18.  
  19. #include <X11/Xos.h>
  20.  
  21. #ifdef HAVE_SYS_SELECT_H
  22. # include <sys/select.h>
  23. #endif
  24.  
  25. #include <time.h>
  26.  
  27. #ifndef X_GETTIMEOFDAY
  28. #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
  29. #endif
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36. typedef struct TimerHandler {
  37.     WMCallback        *callback;           /* procedure to call */
  38.     struct timeval    when;               /* when to call the callback */
  39.     void         *clientData;
  40.     struct TimerHandler *next;
  41. } TimerHandler;
  42.  
  43.  
  44. typedef struct IdleHandler {
  45.     WMCallback        *callback;
  46.     void         *clientData;
  47. } IdleHandler;
  48.  
  49.  
  50. typedef struct InputHandler {
  51.     WMInputProc        *callback;
  52.     void        *clientData;
  53.     int            fd;
  54.     int            mask;
  55. } InputHandler;
  56.  
  57.  
  58. /* table to map event types to event masks */
  59. static unsigned long eventMasks[] = {
  60.     0,
  61.     0,
  62.     KeyPressMask,                       /* KeyPress */
  63.     KeyReleaseMask,                     /* KeyRelease */
  64.     ButtonPressMask,                    /* ButtonPress */
  65.     ButtonReleaseMask,                  /* ButtonRelease */
  66.     PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
  67.             |Button1MotionMask|Button2MotionMask|Button3MotionMask
  68.             |Button4MotionMask|Button5MotionMask,
  69.                                         /* MotionNotify */
  70.     EnterWindowMask,                    /* EnterNotify */
  71.     LeaveWindowMask,                    /* LeaveNotify */
  72.     FocusChangeMask,                    /* FocusIn */
  73.     FocusChangeMask,                    /* FocusOut */
  74.     KeymapStateMask,                    /* KeymapNotify */
  75.     ExposureMask,                       /* Expose */
  76.     ExposureMask,                       /* GraphicsExpose */
  77.     ExposureMask,                       /* NoExpose */
  78.     VisibilityChangeMask,               /* VisibilityNotify */
  79.     SubstructureNotifyMask,             /* CreateNotify */
  80.     StructureNotifyMask,                /* DestroyNotify */
  81.     StructureNotifyMask,                /* UnmapNotify */
  82.     StructureNotifyMask,                /* MapNotify */
  83.     SubstructureRedirectMask,           /* MapRequest */
  84.     StructureNotifyMask,                /* ReparentNotify */
  85.     StructureNotifyMask,                /* ConfigureNotify */
  86.     SubstructureRedirectMask,           /* ConfigureRequest */
  87.     StructureNotifyMask,                /* GravityNotify */
  88.     ResizeRedirectMask,                 /* ResizeRequest */
  89.     StructureNotifyMask,                /* CirculateNotify */
  90.     SubstructureRedirectMask,           /* CirculateRequest */
  91.     PropertyChangeMask,                 /* PropertyNotify */
  92.     0,                                  /* SelectionClear */
  93.     0,                                  /* SelectionRequest */
  94.     0,                                  /* SelectionNotify */
  95.     ColormapChangeMask,                 /* ColormapNotify */
  96.     ClientMessageMask,                /* ClientMessage */
  97.     0,                            /* Mapping Notify */
  98. };
  99.  
  100.  
  101.  
  102. /* queue of timer event handlers */
  103. static TimerHandler *timerHandler=NULL;
  104.  
  105. static WMBag *idleHandler=NULL;
  106.  
  107. static WMBag *inputHandler=NULL;
  108.  
  109. /* hook for other toolkits or wmaker process their events */
  110. static WMEventHook *extraEventHandler=NULL;
  111.  
  112.  
  113.  
  114. #define timerPending()    (timerHandler)
  115.  
  116.  
  117.  
  118. static void
  119. rightNow(struct timeval *tv) {
  120.     X_GETTIMEOFDAY(tv);
  121. }
  122.  
  123. /* is t1 after t2 ? */
  124. #define IS_AFTER(t1, t2)    (((t1).tv_sec > (t2).tv_sec) || \
  125.                  (((t1).tv_sec == (t2).tv_sec) \
  126.                   && ((t1).tv_usec > (t2).tv_usec)))
  127.  
  128.  
  129. static void
  130. addmillisecs(struct timeval *tv, int milliseconds)
  131. {
  132.     tv->tv_usec += milliseconds*1000;
  133.  
  134.     tv->tv_sec += tv->tv_usec/1000000;
  135.     tv->tv_usec = tv->tv_usec%1000000;
  136. }
  137.  
  138.  
  139. WMHandlerID
  140. WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
  141. {
  142.     TimerHandler *handler, *tmp;
  143.     
  144.     handler = malloc(sizeof(TimerHandler));
  145.     if (!handler)
  146.       return NULL;
  147.     
  148.     rightNow(&handler->when);
  149.     addmillisecs(&handler->when, milliseconds);
  150.     handler->callback = callback;
  151.     handler->clientData = cdata;
  152.     /* insert callback in queue, sorted by time left */
  153.     if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
  154.     /* first in the queue */
  155.     handler->next = timerHandler;
  156.     timerHandler = handler;
  157.     } else {
  158.     tmp = timerHandler;
  159.     while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
  160.         tmp = tmp->next;
  161.     }
  162.     handler->next = tmp->next;
  163.     tmp->next = handler;
  164.     }
  165.     return handler;
  166. }
  167.  
  168.  
  169.  
  170. void
  171. WMDeleteTimerWithClientData(void *cdata)
  172. {
  173.     TimerHandler *handler, *tmp;
  174.  
  175.     if (!cdata || !timerHandler)
  176.         return;
  177.  
  178.     tmp = timerHandler;
  179.     if (tmp->clientData==cdata) {
  180.         timerHandler = tmp->next;
  181.         wfree(tmp);
  182.     } else {
  183.         while (tmp->next) {
  184.             if (tmp->next->clientData==cdata) {
  185.                 handler = tmp->next;
  186.                 tmp->next = handler->next;
  187.                 wfree(handler);
  188.                 break;
  189.             }
  190.             tmp = tmp->next;
  191.         }
  192.     }
  193. }
  194.  
  195.  
  196.  
  197. void
  198. WMDeleteTimerHandler(WMHandlerID handlerID)
  199. {
  200.     TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
  201.  
  202.     if (!handler || !timerHandler) 
  203.       return;
  204.  
  205.     tmp = timerHandler;
  206.     if (tmp==handler) {
  207.     timerHandler = handler->next;
  208.     wfree(handler);
  209.     } else {
  210.     while (tmp->next) {
  211.         if (tmp->next==handler) {
  212.         tmp->next=handler->next;
  213.         wfree(handler);
  214.         break;
  215.         }
  216.         tmp = tmp->next;
  217.     }
  218.     }
  219. }
  220.  
  221.  
  222.  
  223. WMHandlerID
  224. WMAddIdleHandler(WMCallback *callback, void *cdata)
  225. {
  226.     IdleHandler *handler;
  227.  
  228.     handler = malloc(sizeof(IdleHandler));
  229.     if (!handler)
  230.         return NULL;
  231.  
  232.     handler->callback = callback;
  233.     handler->clientData = cdata;
  234.     /* add handler at end of queue */
  235.     if (!idleHandler) {
  236.         idleHandler = WMCreateBag(16);
  237.     }
  238.     WMPutInBag(idleHandler, handler);
  239.  
  240.     return handler;
  241. }
  242.  
  243.  
  244.  
  245. void
  246. WMDeleteIdleHandler(WMHandlerID handlerID)
  247. {
  248.     IdleHandler *handler = (IdleHandler*)handlerID;
  249.     int pos;
  250.  
  251.     if (!handler || !idleHandler)
  252.         return;
  253.  
  254.     pos = WMGetFirstInBag(idleHandler, handler);
  255.     if (pos != WBNotFound) {
  256.         wfree(handler);
  257.         WMDeleteFromBag(idleHandler, pos);
  258.     }
  259. }
  260.  
  261.  
  262.  
  263. WMHandlerID
  264. WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
  265. {
  266.     InputHandler *handler;
  267.  
  268.     handler = wmalloc(sizeof(InputHandler));
  269.  
  270.     handler->fd = fd;
  271.     handler->mask = condition;
  272.     handler->callback = proc;
  273.     handler->clientData = clientData;
  274.  
  275.     if (!inputHandler)
  276.         inputHandler = WMCreateBag(16);
  277.     WMPutInBag(inputHandler, handler);
  278.  
  279.     return handler;
  280. }
  281.  
  282.  
  283.  
  284. void
  285. WMDeleteInputHandler(WMHandlerID handlerID)
  286. {
  287.     InputHandler *handler = (InputHandler*)handlerID;
  288.     int pos;
  289.  
  290.     if (!handler || !inputHandler)
  291.     return;
  292.  
  293.     pos = WMGetFirstInBag(inputHandler, handler);
  294.     if (pos != WBNotFound) {
  295.         wfree(handler);
  296.         WMDeleteFromBag(inputHandler, pos);
  297.     }
  298. }
  299.  
  300.  
  301.  
  302. static Bool
  303. checkIdleHandlers()
  304. {
  305.     IdleHandler *handler;
  306.     WMBag *handlerCopy;
  307.     WMBagIterator iter;
  308.  
  309.     if (!idleHandler || WMGetBagItemCount(idleHandler)==0) {
  310.     W_FlushIdleNotificationQueue();
  311.         /* make sure an observer in queue didn't added an idle handler */
  312.         return (idleHandler!=NULL && WMGetBagItemCount(idleHandler)>0);
  313.     }
  314.  
  315.     handlerCopy = WMCreateBag(WMGetBagItemCount(idleHandler));
  316.     WMAppendBag(handlerCopy, idleHandler);
  317.  
  318.     for (handler = WMBagFirst(handlerCopy, &iter);
  319.      iter != NULL;
  320.      handler = WMBagNext(handlerCopy, &iter)) {
  321.         /* check if the handler still exist or was removed by a callback */
  322.         if (WMGetFirstInBag(idleHandler, handler) == WBNotFound)
  323.             continue;
  324.  
  325.     (*handler->callback)(handler->clientData);
  326.         WMDeleteIdleHandler(handler);
  327.     }
  328.  
  329.     WMFreeBag(handlerCopy);
  330.  
  331.     W_FlushIdleNotificationQueue();
  332.  
  333.     /* this is not necesarrily False, because one handler can re-add itself */
  334.     return (WMGetBagItemCount(idleHandler)>0);
  335. }
  336.  
  337.  
  338.  
  339. static void
  340. checkTimerHandlers()
  341. {
  342.     TimerHandler *handler;
  343.     struct timeval now;
  344.  
  345.     if (!timerHandler) {
  346.         W_FlushASAPNotificationQueue();
  347.         return;
  348.     }
  349.  
  350.     rightNow(&now);
  351.  
  352.     while (timerHandler && IS_AFTER(now, timerHandler->when)) {
  353.     handler = timerHandler;
  354.     timerHandler = timerHandler->next;
  355.     handler->next = NULL;
  356.     (*handler->callback)(handler->clientData);
  357.     wfree(handler);
  358.     }
  359.  
  360.     W_FlushASAPNotificationQueue();
  361. }
  362.  
  363.  
  364.  
  365. static void
  366. delayUntilNextTimerEvent(struct timeval *delay)
  367. {
  368.     struct timeval now;
  369.  
  370.     if (!timerHandler) {
  371.         /* The return value of this function is only valid if there _are_
  372.          timers active. */
  373.     delay->tv_sec = 0;
  374.     delay->tv_usec = 0;
  375.     return;
  376.     }
  377.  
  378.     rightNow(&now);
  379.     if (IS_AFTER(now, timerHandler->when)) {
  380.     delay->tv_sec = 0;
  381.     delay->tv_usec = 0;
  382.     } else {
  383.     delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
  384.     delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
  385.     if (delay->tv_usec < 0) {
  386.         delay->tv_usec += 1000000;
  387.         delay->tv_sec--;
  388.     }
  389.     }
  390. }
  391.  
  392.  
  393.              
  394.  
  395. /*
  396.  * WMCreateEventHandler--
  397.  *     Create an event handler and put it in the event handler list for the
  398.  * view. If the same callback and clientdata are already used in another
  399.  * handler, the masks are swapped.
  400.  * 
  401.  */
  402. void
  403. WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
  404.              void *clientData)
  405. {
  406.     W_EventHandler *handler;
  407.     W_EventHandler *ptr = view->handlerList;
  408.     unsigned long eventMask;
  409.         
  410.     if (ptr==NULL) {
  411.     handler = wmalloc(sizeof(W_EventHandler));
  412.  
  413.     handler->nextHandler = NULL;
  414.     
  415.     view->handlerList = handler;
  416.     
  417.     eventMask = mask;
  418.     } else {
  419.     handler = NULL;
  420.     eventMask = mask;
  421.     while (ptr != NULL) {
  422.         if (ptr->clientData == clientData && ptr->proc == eventProc) {
  423.         handler = ptr;
  424.         }        
  425.         eventMask |= ptr->eventMask;
  426.         
  427.         ptr = ptr->nextHandler;
  428.     }
  429.     if (!handler) {
  430.         handler = wmalloc(sizeof(W_EventHandler));
  431.         handler->nextHandler = view->handlerList;
  432.         view->handlerList = handler;
  433.     }    
  434.     }
  435.  
  436.     /* select events for window */
  437.     handler->eventMask = mask;
  438.     handler->proc = eventProc;
  439.     handler->clientData = clientData;
  440. }
  441.  
  442.  
  443. /*
  444.  * WMDeleteEventHandler--
  445.  *     Delete event handler matching arguments from windows
  446.  * event handler list.
  447.  * 
  448.  */
  449. void
  450. WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc, 
  451.              void *clientData)
  452. {
  453.     W_EventHandler *handler, *ptr, *pptr;
  454.     
  455.     ptr = view->handlerList;
  456.     
  457.     handler = NULL;
  458.     pptr = NULL;
  459.     
  460.     while (ptr!=NULL) {
  461.     if (ptr->eventMask == mask && ptr->proc == eventProc 
  462.         && ptr->clientData == clientData) {
  463.         handler = ptr;
  464.         break;
  465.     }
  466.     pptr = ptr;
  467.     ptr = ptr->nextHandler;
  468.     }
  469.     
  470.     if (!handler)
  471.     return;
  472.     
  473.     if (!pptr) {
  474.     view->handlerList = handler->nextHandler;
  475.     } else {
  476.     pptr->nextHandler = handler->nextHandler;
  477.     }
  478.     wfree(handler);
  479. }
  480.  
  481.  
  482.  
  483. void
  484. W_CleanUpEvents(WMView *view)
  485. {
  486.     W_EventHandler *ptr, *nptr;
  487.     
  488.     ptr = view->handlerList;
  489.         
  490.     while (ptr!=NULL) {
  491.     nptr = ptr->nextHandler;
  492.     wfree(ptr);
  493.     ptr = nptr;
  494.     }
  495. }
  496.  
  497.  
  498.  
  499. static Time
  500. getEventTime(WMScreen *screen, XEvent *event)
  501. {
  502.     switch (event->type) {
  503.      case ButtonPress:
  504.      case ButtonRelease:
  505.     return event->xbutton.time;
  506.      case KeyPress:
  507.      case KeyRelease:
  508.     return event->xkey.time;
  509.      case MotionNotify:
  510.     return event->xmotion.time;
  511.      case EnterNotify:
  512.      case LeaveNotify:
  513.     return event->xcrossing.time;
  514.      case PropertyNotify:
  515.     return event->xproperty.time;
  516.      case SelectionClear:
  517.     return event->xselectionclear.time;
  518.      case SelectionRequest:
  519.     return event->xselectionrequest.time;
  520.      case SelectionNotify:
  521.     return event->xselection.time;
  522.      default:
  523.     return screen->lastEventTime;    
  524.     }
  525. }
  526.  
  527.  
  528. void
  529. W_CallDestroyHandlers(W_View *view)
  530. {
  531.     XEvent event;
  532.     W_EventHandler *hPtr;
  533.     
  534.     event.type = DestroyNotify;
  535.     event.xdestroywindow.window = view->window;
  536.     event.xdestroywindow.event = view->window;
  537.     hPtr = view->handlerList;
  538.     while (hPtr!=NULL) {
  539.     if (hPtr->eventMask & StructureNotifyMask) {
  540.         (*hPtr->proc)(&event, hPtr->clientData);
  541.     }
  542.     
  543.     hPtr = hPtr->nextHandler;
  544.     }
  545. }
  546.  
  547.  
  548. int
  549. WMHandleEvent(XEvent *event)
  550. {
  551.     W_EventHandler *hPtr;
  552.     W_View *view, *vPtr, *toplevel;
  553.     unsigned long mask;
  554.     Window window;
  555.  
  556.     if (event->type == MappingNotify) {
  557.     XRefreshKeyboardMapping(&event->xmapping);
  558.     return True;
  559.     }
  560.  
  561.     mask = eventMasks[event->xany.type];
  562.     
  563.     window = event->xany.window;
  564.  
  565.     /* diferentiate SubstructureNotify with StructureNotify */
  566.     if (mask == StructureNotifyMask) {
  567.     if (event->xmap.event != event->xmap.window) {
  568.         mask = SubstructureNotifyMask;
  569.         window = event->xmap.event;
  570.     }
  571.     }
  572.     view = W_GetViewForXWindow(event->xany.display, window);
  573.     if (!view) {
  574.     if (extraEventHandler)
  575.         (extraEventHandler)(event);
  576.  
  577.     return False;
  578.     }
  579.  
  580.     view->screen->lastEventTime = getEventTime(view->screen, event);
  581.  
  582.     toplevel = W_TopLevelOfView(view);
  583.  
  584.     if (event->type == SelectionNotify || event->type == SelectionClear
  585.     || event->type == SelectionRequest) {
  586.     /* handle selection related events */
  587.     W_HandleSelectionEvent(event);
  588.     
  589.     } else if (event->type == ClientMessage) {
  590.     
  591.     W_HandleDNDClientMessage(toplevel, &event->xclient);
  592.     }
  593.  
  594.     /* if it's a key event, redispatch it to the focused control */
  595.     if (mask & (KeyPressMask|KeyReleaseMask)) {
  596.     W_View *focused = W_FocusedViewOfToplevel(toplevel);
  597.     
  598.     if (focused) {
  599.         view = focused;
  600.     }
  601.     }
  602.  
  603.     /* compress Motion events */
  604.     if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
  605.         while (XPending(event->xmotion.display)) {
  606.             XEvent ev;
  607.             XPeekEvent(event->xmotion.display, &ev);
  608.             if (ev.type == MotionNotify 
  609.         && event->xmotion.window == ev.xmotion.window 
  610.         && event->xmotion.subwindow == ev.xmotion.subwindow) {
  611.         /* replace events */
  612.                 XNextEvent(event->xmotion.display, event);
  613.             } else break;
  614.         }
  615.     }
  616.     
  617.     /* compress expose events */
  618.     if (event->type == Expose && !view->flags.dontCompressExpose) {
  619.         while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
  620.                       Expose, event));
  621.     }
  622.  
  623.  
  624.     if (view->screen->modal && toplevel!=view->screen->modalView
  625.     && !toplevel->flags.worksWhenModal) {
  626.     if (event->type == KeyPress || event->type == KeyRelease
  627.         || event->type == MotionNotify || event->type == ButtonPress
  628.         || event->type == ButtonRelease
  629.         || event->type == FocusIn || event->type == FocusOut) {
  630.         return True;
  631.     }
  632.     }
  633.  
  634.     /* do balloon stuffs */
  635.     if (event->type == EnterNotify)
  636.     W_BalloonHandleEnterView(view);
  637.     else if (event->type == LeaveNotify)
  638.     W_BalloonHandleLeaveView(view);
  639.  
  640.     /* This is a hack. It will make the panel be secure while
  641.      * the event handlers are handled, as some event handler
  642.      * might destroy the widget. */
  643.     W_RetainView(toplevel);
  644.  
  645.     hPtr = view->handlerList;
  646.  
  647.     while (hPtr!=NULL) {
  648.     W_EventHandler *tmp;
  649.  
  650.     tmp = hPtr->nextHandler;
  651.  
  652.     if ((hPtr->eventMask & mask)) {
  653.         (*hPtr->proc)(event, hPtr->clientData);
  654.     }
  655.     
  656.     hPtr = tmp;
  657.     }
  658.     
  659.     /* pass the event to the top level window of the widget */
  660.     if (view->parent != NULL) {
  661.     vPtr = view;
  662.     while (vPtr->parent != NULL)
  663.         vPtr = vPtr->parent;
  664.     
  665.     hPtr = vPtr->handlerList;
  666.  
  667.     while (hPtr != NULL) {
  668.     
  669.         if (hPtr->eventMask & mask) {
  670.         (*hPtr->proc)(event, hPtr->clientData);
  671.         }
  672.         hPtr = hPtr->nextHandler;
  673.     }
  674.     }
  675.  
  676.     /* save button click info to track double-clicks */
  677.     if (view->screen->ignoreNextDoubleClick) {
  678.     view->screen->ignoreNextDoubleClick = 0;
  679.     } else {
  680.     if (event->type == ButtonPress) {
  681.         view->screen->lastClickWindow = event->xbutton.window;
  682.         view->screen->lastClickTime = event->xbutton.time;
  683.     }
  684.     }
  685.     
  686.     W_ReleaseView(toplevel);
  687.     
  688.     return True;
  689. }
  690.  
  691.  
  692. int
  693. WMIsDoubleClick(XEvent *event)
  694. {
  695.     W_View *view;
  696.     
  697.     if (event->type != ButtonPress)
  698.     return False;
  699.     
  700.     view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
  701.  
  702.     if (!view)
  703.     return False;
  704.     
  705.     if (view->screen->lastClickWindow != event->xbutton.window)
  706.     return False;
  707.     
  708.     if (event->xbutton.time - view->screen->lastClickTime 
  709.     < WINGsConfiguration.doubleClickDelay) {
  710.     view->screen->lastClickTime = 0;
  711.     view->screen->lastClickWindow = None;
  712.     view->screen->ignoreNextDoubleClick = 1;
  713.     return True;
  714.     } else
  715.     return False;
  716. }
  717.  
  718.  
  719. Bool
  720. W_WaitForEvent(Display *dpy, unsigned long xeventmask)
  721. {
  722. #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
  723.     struct pollfd *fds;
  724.     InputHandler *handler;
  725.     int count, timeout, nfds, i, retval;
  726.  
  727.     if (inputHandler)
  728.         nfds = WMGetBagItemCount(inputHandler);
  729.     else
  730.         nfds = 0;
  731.  
  732.     fds = wmalloc(nfds+1 * sizeof(struct pollfd));
  733.     /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
  734.     fds[nfds].fd = ConnectionNumber(dpy);
  735.     fds[nfds].events = POLLIN;
  736.  
  737.     for (i = 0; i<nfds; i++) {
  738.         handler = WMGetFromBag(inputHandler, i);
  739.         fds[i].fd = handler->fd;
  740.         fds[i].events = 0;
  741.         if (handler->mask & WIReadMask)
  742.             fds[i].events |= POLLIN;
  743.  
  744.         if (handler->mask & WIWriteMask)
  745.             fds[i].events |= POLLOUT;
  746.  
  747. #if 0 /* FIXME */
  748.         if (handler->mask & WIExceptMask)
  749.             FD_SET(handler->fd, &eset);
  750. #endif
  751.     }
  752.  
  753.     /*
  754.      * Setup the select() timeout to the estimated time until the
  755.      * next timer expires.
  756.      */
  757.     if (timerPending()) {
  758.         struct timeval tv;
  759.     delayUntilNextTimerEvent(&tv);
  760.         timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
  761.     } else {
  762.         timeout = -1;
  763.     }
  764.  
  765.     if (xeventmask==0) {
  766.     if (XPending(dpy))      
  767.         return True;
  768.     } else {
  769.     XEvent ev;
  770.     if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
  771.         XPutBackEvent(dpy, &ev);
  772.         return True;
  773.     }
  774.     }
  775.     
  776.     count = poll(fds, nfds, timeout);
  777.  
  778.     if (count>0 && nfds>0) {
  779.         WMBag *handlerCopy = WMCreateBag(nfds);
  780.  
  781.         for (i=0; i<nfds; i++)
  782.             WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
  783.  
  784.         for (i=0; i<nfds; i++) {
  785.         int mask;
  786.  
  787.             handler = WMGetFromBag(handlerCopy, i);
  788.             /* check if the handler still exist or was removed by a callback */
  789.             if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
  790.                 continue;
  791.  
  792.         mask = 0;
  793.  
  794.             if ((handler->mask & WIReadMask) &&
  795.                 (fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
  796.                 mask |= WIReadMask;
  797.  
  798.             if ((handler->mask & WIWriteMask) &&
  799.                 (fds[i].revents & (POLLOUT | POLLWRBAND)))
  800.                 mask |= WIWriteMask;
  801.  
  802.             if ((handler->mask & WIExceptMask) &&
  803.                 (fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
  804.                 mask |= WIExceptMask;
  805.  
  806.         if (mask!=0 && handler->callback) {
  807.         (*handler->callback)(handler->fd, mask, 
  808.                      handler->clientData);
  809.         }
  810.         }
  811.  
  812.         WMFreeBag(handlerCopy);
  813.     }
  814.  
  815.     retval = fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
  816.     wfree(fds);
  817.  
  818.     W_FlushASAPNotificationQueue();
  819.  
  820.     return retval;
  821. #else /* not HAVE_POLL */
  822. #ifdef HAVE_SELECT
  823.     struct timeval timeout;
  824.     struct timeval *timeoutPtr;
  825.     fd_set rset, wset, eset;
  826.     int maxfd, nfds, i;
  827.     int count;
  828.     InputHandler *handler;
  829.  
  830.     FD_ZERO(&rset);
  831.     FD_ZERO(&wset);
  832.     FD_ZERO(&eset);
  833.  
  834.     FD_SET(ConnectionNumber(dpy), &rset);
  835.     maxfd = ConnectionNumber(dpy);
  836.  
  837.     if (inputHandler)
  838.         nfds = WMGetBagItemCount(inputHandler);
  839.     else
  840.         nfds = 0;
  841.  
  842.     for (i=0; i<nfds; i++) {
  843.         handler = WMGetFromBag(inputHandler, i);
  844.     if (handler->mask & WIReadMask)
  845.         FD_SET(handler->fd, &rset);
  846.  
  847.     if (handler->mask & WIWriteMask)
  848.         FD_SET(handler->fd, &wset);
  849.  
  850.     if (handler->mask & WIExceptMask)
  851.         FD_SET(handler->fd, &eset);
  852.  
  853.     if (maxfd < handler->fd)
  854.         maxfd = handler->fd;
  855.     }
  856.  
  857.  
  858.     /*
  859.      * Setup the select() timeout to the estimated time until the
  860.      * next timer expires.
  861.      */
  862.     if (timerPending()) {
  863.     delayUntilNextTimerEvent(&timeout);
  864.     timeoutPtr = &timeout;
  865.     } else {
  866.     timeoutPtr = (struct timeval*)0;
  867.     }
  868.  
  869.     XSync(dpy, False);
  870.     if (xeventmask==0) {
  871.     if (XPending(dpy))
  872.         return True;
  873.     } else {
  874.     XEvent ev;
  875.     if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
  876.         XPutBackEvent(dpy, &ev);
  877.         return True;
  878.     }
  879.     }
  880.  
  881.     count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
  882.  
  883.     if (count>0 && nfds>0) {
  884.         WMBag *handlerCopy = WMCreateBag(nfds);
  885.  
  886.         for (i=0; i<nfds; i++)
  887.             WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
  888.  
  889.         for (i=0; i<nfds; i++) {
  890.         int mask;
  891.  
  892.             handler = WMGetFromBag(handlerCopy, i);
  893.             /* check if the handler still exist or was removed by a callback */
  894.             if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
  895.                 continue;
  896.  
  897.         mask = 0;
  898.  
  899.         if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
  900.         mask |= WIReadMask;
  901.  
  902.         if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
  903.         mask |= WIWriteMask;
  904.  
  905.         if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
  906.         mask |= WIExceptMask;
  907.  
  908.         if (mask!=0 && handler->callback) {
  909.         (*handler->callback)(handler->fd, mask, 
  910.                      handler->clientData);
  911.         }
  912.         }
  913.  
  914.         WMFreeBag(handlerCopy);
  915.     }
  916.  
  917.     W_FlushASAPNotificationQueue();
  918.  
  919.     return FD_ISSET(ConnectionNumber(dpy), &rset);
  920. #else /* not HAVE_SELECT, not HAVE_POLL */
  921. Neither select nor poll. You lose.
  922. #endif /* HAVE_SELECT */
  923. #endif /* HAVE_POLL */
  924. }
  925.  
  926.  
  927. void
  928. WMNextEvent(Display *dpy, XEvent *event)
  929.     /* Check any expired timers */
  930.     checkTimerHandlers();
  931.  
  932.     while (XPending(dpy) == 0) {
  933.     /* Do idle stuff */
  934.     /* Do idle and timer stuff while there are no timer or X events */
  935.     while (!XPending(dpy) && checkIdleHandlers()) {
  936.         /* dispatch timer events */
  937.             checkTimerHandlers();
  938.     }
  939.  
  940.     /*
  941.      * Make sure that new events did not arrive while we were doing
  942.      * timer/idle stuff. Or we might block forever waiting for
  943.      * an event that already arrived. 
  944.      */
  945.     /* wait to something happen */
  946.     W_WaitForEvent(dpy, 0);
  947.     
  948.         /* Check any expired timers */
  949.         checkTimerHandlers();
  950.     }
  951.  
  952.     XNextEvent(dpy, event);
  953. }
  954.  
  955. #if 0
  956. void
  957. WMMaskEvent(Display *dpy, long mask, XEvent *event)
  958.     unsigned long milliseconds;
  959.     struct timeval timeout;
  960.     struct timeval *timeoutOrInfty;
  961.     fd_set readset;
  962.  
  963.     while (!XCheckMaskEvent(dpy, mask, event)) {
  964.     /* Do idle stuff while there are no timer or X events */
  965.     while (checkIdleHandlers()) {
  966.         if (XCheckMaskEvent(dpy, mask, event))
  967.         return;
  968.     }
  969.            
  970.         /* 
  971.          * Setup the select() timeout to the estimated time until the
  972.          * next timer expires.
  973.          */
  974.         if (timerPending()) {
  975.         delayUntilNextTimerEvent(&timeout);
  976.             timeoutOrInfty = &timeout;
  977.         } else {
  978.             timeoutOrInfty = (struct timeval*)0;
  979.         }
  980.  
  981.     if (XCheckMaskEvent(dpy, mask, event))
  982.         return;
  983.  
  984.         /* Wait for input on the X connection socket */
  985.     FD_ZERO(&readset);
  986.     FD_SET(ConnectionNumber(dpy), &readset);
  987.     select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
  988.            timeoutOrInfty);
  989.  
  990.         /* Check any expired timers */
  991.         checkTimerHandlers();
  992.     }
  993. }
  994. #endif
  995. #if 1
  996. /*
  997.  * Cant use this because XPending() will make W_WaitForEvent
  998.  * return even if the event in the queue is not what we want,
  999.  * and if we block until some new event arrives from the
  1000.  * server, other events already in the queue (like Expose)
  1001.  * will be deferred.
  1002.  */
  1003. void
  1004. WMMaskEvent(Display *dpy, long mask, XEvent *event)
  1005.     while (!XCheckMaskEvent(dpy, mask, event)) {
  1006.     /* Do idle stuff while there are no timer or X events */
  1007.     while (checkIdleHandlers()) {
  1008.         if (XCheckMaskEvent(dpy, mask, event))
  1009.         return;
  1010.     }
  1011.  
  1012.         /* Wait for input on the X connection socket */
  1013.     W_WaitForEvent(dpy, mask);
  1014.  
  1015.         /* Check any expired timers */
  1016.         checkTimerHandlers();
  1017.     }
  1018. }
  1019. #endif
  1020.  
  1021. Bool 
  1022. WMScreenPending(WMScreen *scr)
  1023. {
  1024.     if (XPending(scr->display))
  1025.     return True;
  1026.     else
  1027.     return False;
  1028. }
  1029.  
  1030.  
  1031. WMEventHook*
  1032. WMHookEventHandler(WMEventHook *handler)
  1033. {
  1034.     WMEventHook *oldHandler = extraEventHandler;
  1035.     
  1036.     extraEventHandler = handler;
  1037.     
  1038.     return oldHandler;
  1039. }
  1040.  
  1041.  
  1042.